package com.huatai.verity.utils;

import lombok.extern.slf4j.Slf4j;
import org.dom4j.Document;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.dom4j.io.OutputFormat;
import org.dom4j.io.XMLWriter;
import org.springframework.util.Base64Utils;

import javax.crypto.*;
import javax.crypto.spec.SecretKeySpec;

import java.io.File;
import java.io.FileWriter;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.security.SecureRandom;
import java.util.HashMap;
import java.util.Map;


/**
 * @program: ht-system
 * @description: AES
 * @author: songxiude
 * @create: 2023-07-20 15:03
 **/
@Slf4j
public class AESUtils {

	/**
	 * RSA加密后的AES秘钥
	 */
	private static String aesEncyptPwd="e2uyZ+mWZ70PmWBVPNn66gRbIKtlEYLfjH6d8XaPpqcIfmLjQtoSBVcPRRdsVBgqpMhqtaUm2qr/AWV7tzfoQ8T2ZxGmkyfUYECXS18dye+AvcSt9AEC1cPPAZQxF/PPOf9PoS/BhXkCIIft6Rlv8QBhYQHxKyu57jeI3zUskpw=";

	private static final String KEY_ALGORITHM = "AES";

	private static final String DEFAULT_CIPHER_ALGORITHM = "AES/ECB/PKCS5Padding";

	/**
	 * AES 加密操作
	 *
	 * @param content  待加密内容
	 * @return 返回Base64转码后的加密数据
	 */
	public static String encrypt(String content) {
		try {
			Cipher cipher = Cipher.getInstance(DEFAULT_CIPHER_ALGORITHM);
			byte[] byteContent = content.getBytes("utf-8");
			cipher.init(Cipher.ENCRYPT_MODE, getSecretKey(RSAUtils.decrypt(aesEncyptPwd)));
			byte[] result = cipher.doFinal(byteContent);
			return Base64Utils.encodeToString(result);
		} catch (Exception ex) {
			ex.printStackTrace();
			System.out.println("AES加密失败");
		}

		return null;
	}

	/**
	 * AES 解密操作
	 *
	 * @param content  已加密内容
	 * @return
	 */
	public static String decrypt(String content) {
		try {
			//实例化
			Cipher cipher = Cipher.getInstance(DEFAULT_CIPHER_ALGORITHM);
			//使用密钥初始化，设置为解密模式
			cipher.init(Cipher.DECRYPT_MODE, getSecretKey(RSAUtils.decrypt(aesEncyptPwd)));
			//执行操作
			byte[] result = cipher.doFinal(Base64Utils.decodeFromString(content));
			return new String(result, "utf-8");
		} catch (Exception ex) {
			ex.printStackTrace();
			System.out.println("AES解密失败");
		}
		return null;
	}

	/**
	 * 生成加密秘钥
	 *
	 * @return
	 */
	public static SecretKeySpec getSecretKey(String aesKey) {
		//返回生成指定算法密钥生成器的 KeyGenerator 对象
		KeyGenerator kg = null;
		try {
			kg = KeyGenerator.getInstance(KEY_ALGORITHM);
			//AES 要求密钥长度为 128
			SecureRandom random=SecureRandom.getInstance("SHA1PRNG","SUN");
			random.setSeed(aesKey.getBytes());
			kg.init(128, random);
			//生成一个密钥
			SecretKey secretKey = kg.generateKey();
			return new SecretKeySpec(secretKey.getEncoded(), KEY_ALGORITHM);
		} catch (NoSuchAlgorithmException ex) {
			ex.printStackTrace();
			System.out.println("生成加密秘钥失败");
		} catch (NoSuchProviderException e) {
			e.printStackTrace();
			System.out.println("生成加密秘钥失败");
		}
		return null;
	}

	public static void createLicense(String systemSign, String generatedTimeStr, String expiredTimeStr, String lastValidateTimeStr, String version, String path) {
		try {
			//解密系统标识得到mac地址+cpu序列号
			String sysNumber = AESUtils.decrypt(systemSign);
			System.out.println("客户服务器mac地址和cpu序列号：" + sysNumber);

			//系统序列号-生效起始时间-生效结束结束时间-软件产品序列号（项目版本唯一标识）
//            String content = "B23540D3BF8470E47B481176830F410E9-20220506-20220507-dmoiji3xkoa4p33";
			StringBuilder signBuilder = new StringBuilder(sysNumber);
			//生效起始时间
			long generatedTime = DateUtils.getTimeInMillis(generatedTimeStr);
			//生效截止时间
			long expiredTime = DateUtils.getTimeInMillis(expiredTimeStr);
			System.out.println(expiredTime);
			//项目唯一标识
			signBuilder.append("-").append(generatedTime).append("-").append(expiredTime).append("-").append(version);

			String sign = AESUtils.encrypt(signBuilder.toString());
			System.out.println("AES加密生成签名：");
			System.out.println("-----------------------------------------------------------------------------------------------");
			System.out.println(sign);
			System.out.println("-----------------------------------------------------------------------------------------------");

			//生成licence文件
			Document document = DocumentHelper.createDocument();
			//根节点
			Element rootEle = document.addElement("license");
			//功能数据节点,扩展参数时可在此节点下扩展
			Element dataEle = rootEle.addElement("features");
			Element featureEle = dataEle.addElement("feature");
			featureEle.addAttribute("name", "lastValidateTi");
			featureEle.addAttribute("ti", AESUtils.encrypt(String.valueOf(DateUtils.getTimeInMillis(lastValidateTimeStr))));
			//签名节点
			Element signEle = rootEle.addElement("signature");
			signEle.setText(sign);
			System.out.println(document.asXML());
			OutputFormat format = OutputFormat.createPrettyPrint();
			// 设置编码格式
			format.setEncoding("UTF-8");
			FileWriter fileWriter = new FileWriter(new File(path));
			XMLWriter xmlWriter = new XMLWriter(fileWriter, format);
			// 设置是否转义，默认使用转义字符
			xmlWriter.setEscapeText(false);
			xmlWriter.write(document);
			xmlWriter.close();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	/**
	 * 获取授权签名
	 * @param systemSign
	 * @param generatedTimeStr
	 * @param expiredTimeStr
	 * @param lastValidateTimeStr
	 * @param version
	 * @return
	 */
	public static Map<String,String> getLicense(String systemSign, String generatedTimeStr, String expiredTimeStr, String lastValidateTimeStr, String version) {
		try {
			HashMap<String, String> map = new HashMap<>();
			//解密系统标识得到mac地址+cpu序列号
			String sysNumber = AESUtils.decrypt(systemSign);
			log.info("sysNumber:{}",sysNumber);

			//系统序列号-生效起始时间-生效结束结束时间-软件产品序列号（项目版本唯一标识）
//            String content = "B23540D3BF8470E47B481176830F410E9-20220506-20220507-dmoiji3xkoa4p33";
			StringBuilder signBuilder = new StringBuilder(sysNumber);
			//生效起始时间
			long generatedTime = DateUtils.getTimeInMillis(generatedTimeStr);
			//生效截止时间
			long expiredTime = DateUtils.getTimeInMillis(expiredTimeStr);
			//项目唯一标识
			signBuilder.append("-").append(generatedTime).append("-").append(expiredTime).append("-").append(version);

			String sign = AESUtils.encrypt(signBuilder.toString());

			String ti = AESUtils.encrypt(String.valueOf(DateUtils.getTimeInMillis(lastValidateTimeStr)));
			map.put("ti",ti);
			map.put("sign",sign);
			log.info("ti:{}---sign:{}",ti,sign);
			return map;

		} catch (Exception e) {
			e.printStackTrace();
		}
		return null;
	}

}
